package com.listen.common;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.IOUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.List;
import java.util.*;

/**
 * 水利建造师
 * 识别图片验证码-数字或字母
 * @author rain
 *
 */
public class ShuiliPictureVerificationCode {
	private static String url = "http://passport2.chaoxing.com/num/code?t="+System.currentTimeMillis();

	public static void main(String[] args) throws Exception {
		ShuiliPictureVerificationCode instance = new ShuiliPictureVerificationCode();
		//下载图片
		//instance.downloadImage(url);
		//instance.readDictionary();
		getVerificationCode(url,true);

	}


	//1-获取验证码图片
	private String downloadImage(String picUrl) {
		String name = DateFormatUtil.getDateStr(new Date(),"yyyyMMddHHmmss");
		String picName = getbaseImgaeUrl() + name + ".jpg";
		try {
			BufferedImage image = ImageIO.read(new URL(picUrl));
			File file = new File(picName);
			ImageIO.write(image, "jpg", file);
		} catch (IOException ignored) {
			ignored.printStackTrace();
		}
		return picName;
	}

	//设置图片本地保存路径
	private static String getbaseImgaeUrl() {
		return System.getProperty("os.name").toLowerCase()
				.startsWith("win") ? "D:\\photos\\shuili\\" : "/home/listen/photos/shuili/";
	}

	/**
	 * 获取识别后的验证码
	 * @param param	needLoadImage为true时，param为验证码图片加载链接，false时为图片全路径名称
	 * @param needLoadImage	是否需要加载图片
	 * @return
	 */
	public static String getVerificationCode(String param,boolean needLoadImage) {
		ShuiliPictureVerificationCode instance = new ShuiliPictureVerificationCode();
		try {
			String picName = "";
			if(needLoadImage) {
				picName = instance.downloadImage(param);
			}else {
				picName = param;
			}

			File file = new File(picName);
			BufferedImage img = instance.removeBackgroud(file);
			//保存去噪点后的图片
			ImageIO.write(img, "jpg", file);

			//切割后的四张图片
			List<BufferedImage> images = instance.spiltImage(instance.spilt(instance.convert(img)), img);
			for(int k = 0;k<images.size();k++) {
				ImageIO.write(images.get(k), "jpg", new File("D:\\photos\\shuili\\split\\"+k+".jpg"));
			}
		    String code = instance.comparing(instance.getBin(images));
		    System.out.println(code);
		    return code;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * 获取识别后的验证码
	 * @return
	 */
	public static List<String> getBinaryList(String picName) {
		ShuiliPictureVerificationCode instance = new ShuiliPictureVerificationCode();
		try {
			File file = new File(picName);
			BufferedImage image = ImageIO.read(file);
			image = instance.removeBackgroud(file);
			//切割后的四张图片
			List<BufferedImage> images = instance.spiltImage(instance.spilt(instance.convert(image)), image);
			return instance.comparing2(instance.getBin(images));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	//2-去除图片噪点  并将彩色转为纯色(黑色)
	public BufferedImage removeBackgroud(File picFile)
			throws Exception {
		BufferedImage img = ImageIO.read(picFile);
		int width = img.getWidth();
		int height = img.getHeight();
		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				if (isWhite(img.getRGB(x, y)) == 1) {
					img.setRGB(x, y, Color.WHITE.getRGB());
				} else {
					img.setRGB(x, y, Color.BLACK.getRGB());
				}
			}
		}
		return img;
	}

	//2-去噪点和干扰线
	public BufferedImage removeInterference(BufferedImage image) {
	    int width = image.getWidth();
	    int height = image.getHeight();
	    for (int x = 0; x < width; x++) {
	        for (int y = 0; y < height; y++) {
	            boolean c = true;
	            // 这个像素块上下左右是不是都是黑色的,如果是,这个像素当作黑色的
	            int roundWhiteCount = 0;
	            if (isBlackColor(image, x + 1, y + 1))
	                roundWhiteCount++;
	            if (isBlackColor(image, x + 1, y - 1))
	                roundWhiteCount++;
	            if (isBlackColor(image, x - 1, y + 1))
	                roundWhiteCount++;
	            if (isBlackColor(image, x - 1, y - 1))
	                roundWhiteCount++;
	            if (roundWhiteCount >= 4) {
	                c = false;
	            }

	            if (!isBlackColor(image, x, y) && c) {
	                image.setRGB(x, y, 0xFFFFFFFF); //argb:AARRGGBB
	            }
	        }
	    }
	    return allBlack(image);
	}

	//3-切割验证码图片
	public List<BufferedImage> spiltImage(List<int[]> list, BufferedImage image) {
	    final int DIGIT_Y = 0;
	    final int DIGIT_HEIGHT = image.getHeight();

	    List<BufferedImage> digitImageList = new LinkedList<>();
	    digitImageList.add(image.getSubimage(list.get(0)[0] - 1, DIGIT_Y, list.get(0)[1] - list.get(0)[0] + 1, DIGIT_HEIGHT));
	    digitImageList.add(image.getSubimage(list.get(1)[0] - 1, DIGIT_Y, list.get(1)[1] - list.get(1)[0] + 1, DIGIT_HEIGHT));
	    digitImageList.add(image.getSubimage(list.get(2)[0] - 1, DIGIT_Y, list.get(2)[1] - list.get(2)[0] + 1, DIGIT_HEIGHT));
	    digitImageList.add(image.getSubimage(list.get(3)[0] - 1, DIGIT_Y, list.get(3)[1] - list.get(3)[0] + 1, DIGIT_HEIGHT));

	    return digitImageList;
	}

	//4-获取整张验证码图片的二进制字符集
	public List<String> getBin(List<BufferedImage> images) {
	    List<String> list = new LinkedList<>();
	    for (BufferedImage image : images) {
	        StringBuilder reslut = new StringBuilder();
	        for (int w = 0; w < image.getWidth(); w++) {
	            for (int h = 0; h < image.getHeight(); h++) {
	                if ((image.getRGB(w, h) & 0xFFFFFF) == (new Color(0, 0, 0).getRGB() & 0xFFFFFF)) {
	                    reslut.append("1");
	                } else {
	                    reslut.append("0");
	                }
	            }
	        }
	        list.add(reslut.toString());
	    }
	    return list;
	}

	//5-将切割并手工归并后的图片二进制化并存入字典
	public Map<String, String> loadTrainData11() throws Exception {
		Map<String, String> map = new HashMap<String, String>();
		for(int num = 0; num < 10; num++) {
			File dir = new File(getbaseImgaeUrl()+num);
			File[] files = dir.listFiles();
			for (File file : files) {
				//System.out.println(file.getName().charAt(0));
				BufferedImage image = ImageIO.read(file);
				//map.put(getBin(image), file.getName().charAt(0) + "");
				String conent = getBin(image) + "=" + file.getName().charAt(0);
				//System.out.println(conent);
				saveDictionary(conent);
			}
		}
		return map;
	}

	//6-根据字典对比
	private String comparing(List<String> lists) throws Exception {
		Map<String, String> dictionary = this.readDictionary();
	    StringBuilder reslut = new StringBuilder();
	    for (String s : lists) {
	        int minCount = s.length();
	        String re = "";
	        for (Map.Entry<String, String> dic : dictionary.entrySet()) {
	            // 一一比较
	            String d = dic.getKey();
	            int count = 0;
	            one:
	            if (d.length() == s.length()) {
	                for (int n = 0; n < s.length() - 1; n++) {
	                	//循环统计不相等的位数,最后差异最小的，即是我们要的数字
	                    if (!s.substring(n, n + 1).equals(d.substring(n, n + 1))) {
	                        count++;
	                    }
	                    if (count >= minCount) {
	                        break one;
	                    }
	                }
	            } else {
	                continue;
	            }
	            if (count < minCount) {
	                minCount = count;
	                re = dic.getValue();
	            }
	        }
	        reslut.append(re);
	    }
	    return reslut.toString();
	}

	private List<String> comparing2(List<String> lists) throws Exception {
		Map<String, String> dictionary = this.readDictionary();
		List<String> list = new ArrayList<String>();
	    for (String s : lists) {
	        int minCount = s.length();
	        String re = "";
	        for (Map.Entry<String, String> dic : dictionary.entrySet()) {
	            // 一一比较
	            String d = dic.getKey();
	            int count = 0;
	            one:
	            if (d.length() == s.length()) {
	                for (int n = 0; n < s.length() - 1; n++) {
	                	//循环统计不相等的位数,最后差异最小的，即是我们要的数字
	                    if (!s.substring(n, n + 1).equals(d.substring(n, n + 1))) {
	                        count++;
	                    }
	                    if (count >= minCount) {
	                        break one;
	                    }
	                }
	            } else {
	                continue;
	            }
	            if (count < minCount) {
	                minCount = count;
	                re = dic.getValue();
	            }
	        }
	        list.add(s+"="+re);
	    }
	    return list;
	}

	//设置颜色阀值
	public static int isWhite(int colorInt) {
		Color color = new Color(colorInt);
		if (color.getRed() + color.getGreen() + color.getBlue() > 280 && color.getRed() + color.getGreen() + color.getBlue()<660) {
			return 0;
		}
		return 1;
	}

	public BufferedImage allBlack(BufferedImage image) {
	    int width = image.getWidth();
	    int height = image.getHeight();
	    for (int x = 0; x < width; x++) {
	        for (int y = 0; y < height; y++) {
	            // 不是纯白就填黑
	            if ((image.getRGB(x, y) & 0xFFFFFF) != (new Color(255, 255, 255).getRGB() & 0xFFFFFF)) {
	                image.setRGB(x, y, 0xFF000000);
	            }
	        }
	    }
	    return image;
	}

	private boolean isBlackColor(BufferedImage image, int x, int y) {
	    // 检查这个像素块是不是边缘的
	    if (x < 0 || y < 0 || x >= image.getWidth() || y >= image.getHeight()) {
	        return false;
	    }
	    int pixel = image.getRGB(x, y);
	    //System.out.println((pixel & 0xFF0000) >> 16);
	    return
	            // R
	            (pixel & 0xFF0000) >> 16 < 155
	             // G
	             && (pixel & 0xFF00) >> 8 < 155
	             // B
	             && (pixel & 0xFF) < 155;
	}

	private List<Integer> convert(BufferedImage image) {
	    List<Integer> source = new LinkedList<>();
	    int width = image.getWidth();
	    int height = image.getHeight();
	    for (int x = 0; x < width; x++) {
	        int count = 0;
	        // 计算黑块总数
	        for (int y = 0; y < height; y++) {
	            if (isBlackColor(image, x, y)) {
	                count++;
	            }
	        }
	        source.add(count);
	    }
	    return source;
	}
	// 分割convert() return 的List
	private List<int[]> spilt(List<Integer> source) {
	    List<int[]> reslut = new LinkedList<>();
	    for (int n = 0, count = 0; n < source.size(); n++) {
	        if (source.get(n) != 0) {
	            count++;
	        } else if (count > 2 || (n > 2 && source.get(n - 1) + source.get(n - 2) > 3)) {
	            if (source.subList(n - count, n).size() > 1) {
	                reslut.add(new int[]{n - count + 1, n});
	            }
	            count = 0;
	        }
	    }
	    return reslut;
	}

	//获取单个文字|数字的二进制字符集
	private String getBin(BufferedImage image) {
		StringBuilder reslut = new StringBuilder();
	    for (int w = 0; w < image.getWidth(); w++) {
            for (int h = 0; h < image.getHeight(); h++) {
                if ((image.getRGB(w, h) & 0xFFFFFF) == (new Color(0, 0, 0).getRGB() & 0xFFFFFF)) {
                    reslut.append("1");
                } else {
                    reslut.append("0");
                }
            }
        }
	    return reslut.toString();
	}
	
	public static boolean deleteFile(String fileName) {
		return new File(fileName).delete();
	}
	
	/**
	 * 往本地文件追加內容
	 * @param conent
	 */
	public static void saveDictionary(String conent) {
		BufferedWriter out = null;
		String dictionaryName = getbaseImgaeUrl() + "dictionary.txt";
		try {
			out = new BufferedWriter(new OutputStreamWriter(
					new FileOutputStream(dictionaryName, true)));
			out.write(conent+"\r\n");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 从本地文件中逐行读取内容
	 */
	public Map<String, String> readDictionary() {
		Map<String, String> map = new HashMap<String, String>();
		FileReader reader = null;
		BufferedReader bfReader = null;
		String dictionaryName = getbaseImgaeUrl() + "dictionary.txt";
		try {
			reader = new FileReader(dictionaryName);
			bfReader = new BufferedReader(reader);
			String line = "";
			while((line = bfReader.readLine()) != null) {
				map.put(line.split("=")[0], line.split("=")[1]);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				reader.close();
				bfReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		return map;
	}
}
